<?php
defined('IN_MAIN') or exit('Invalid Access!');

function calc_pairing_matching($in_year, $in_month, $in_day){
/*
This function calculate the pairing and matching bonus for the input in_date. This function will get all the purchases that is the first
purchase for a particular user (second and onwards purchase for a user will be calculated for another commission) for the input in_date and 
calculate the pairing in such a way that A will pair with B, then leftover from this pairing will pair with C, and leftover will pair
with D, and so on, until a point that the next downline does not have sufficient volume to continue the pairing, or the number pairing reaches
10 pairs per day. If D in this case does not have enough volume to pair, then it will stop here, and if there are further downlines like E,F,G
that have enough volume, pairing will not continue too. And the leftover from the pairing and all other unpaired downline (in above case E,F,G) 
will be carried forward for next day pairing. After pairing, the matching will calculate right away to the sponsor of the commission receiver.

On successful commission calculation, it will return boolean true, else it will return the error messages
*/

	//globalize access to pairing_amount_per_pair, pairing_bonus_per_pair, max_pair_per_day, matching_bonus
	
	global $vars;
	$db=$vars["db"];
	$pairing_amount_per_pair = $vars['pairing_amount_per_pair'];
	$pairing_bonus_per_pair = $vars['pairing_bonus_per_pair'];
	$max_pair_per_day = $vars['max_pair_per_day'];
	$matching_bonus = $vars['matching_bonus'];
	
	$start_time=mktime(0, 0, 0, $in_month, $in_day, $in_year);
	$calc_date['start']=date('Y-m-d H:i:s', mktime(0, 0, 0, $in_month, $in_day, $in_year));
	$calc_date['end']=date('Y-m-d H:i:s', mktime(23, 59, 59, $in_month, $in_day, $in_year));
	$calc_date2['start']=date('Y-m-d H:i:s', mktime(0, 0, 0, $in_month, 1, $in_year));
	$calc_date2['end']=date('Y-m-d H:i:s', mktime(23, 59, 59, $in_month+1, 0, $in_year));
	
	//matching_max_level = get the maximum of matching level
	//min_maintain = get the minimum maintenance
	$matching_max_level = count($matching_bonus);
	$min_maintain = $vars['min_maintain'];
	
	//xxx members = get all the members xxx - we don't we need to filter by maintain 200 as filter is done at reporting - that have personal maintain / purchases of more than min_maintain (200)
	//xxx members = get all the members that have maintain 200BV purchases in the month
	//members = get all the members that is activated
	$t=@mysql_num_rows($r=mysql_query("select id from $db->users where activated='y'"));
	
	//foreach members
	for($i=0;$i<$t;$i++){
		$member = mysql_fetch_assoc($r);
		//uid = this member[id]
		$uid = $member['id'];
		//member_legs = get_member_matrix_leg(this member ID, calc_date[start], calc_date[end]) //get this member all legs
		$member_legs = get_member_matrix_leg($uid, $calc_date['start'], $calc_date['end']);
		/*
			member_legs will then looks like this:
			member_legs[index][id]
			member_legs[index][position]
			member_legs[index][volume] - volume should include this day volume (1st sale of a member only) plus any carry forward from previous day if applicable
			member_legs[index][left_volume] - same with volume
			member_legs[index][avolume] - avolume should include only this day volume (1st sale of a member only), without any carry forward
			
			position is the matrix position, avolume is total purchases for this day, sort by largest volume (include carry forward) leg 1st
		*/
		//total_paired = 0
		//prev_position = 0
		//cur_position = 1
		//pi = 0
		$total_paired = 0;
		$prev_position = 0;
		$cur_position = 1;
		$pi = 0;
		do{
			//continue_pair = false
			$continue_pair = false;
			//if total_paired < max_pair_per_day
			if ($total_paired < $max_pair_per_day){
				//if isset member_legs[prev_position] and isset member_legs[cur_position]
				if (isset($member_legs[$prev_position]) && isset($member_legs[($cur_position)])){
					//if member_legs[prev_position][left_volume] >= pairing_amount_per_pair and member_legs[cur_position][volume] >= pairing_amount_per_pair
					if ($member_legs[$prev_position]['left_volume'] >= $pairing_amount_per_pair && $member_legs[$cur_position]['volume'] >= $pairing_amount_per_pair){
						//paired_amount = the least of member_legs[prev_position][left_volume] and member_legs[cur_position][volume]
						//paired_unit = floor(paired_amount / pairing_amount_per_pair)
						$paired_amount = ($a = $member_legs[$prev_position]['left_volume']) > ($b = $member_legs[$cur_position]['volume'])? $b : $a;
						$paired_unit = floor($paired_amount / $pairing_amount_per_pair);
						//if total_paired + paired_unit > max_pair_per_day
						if ($total_paired + $paired_unit > $max_pair_per_day){
							//paired_unit = max_pair_per_day - total_paired
							$paired_unit = $max_pair_per_day - $total_paired;
						}
						//paired_amount = paired_unit * pairing_amount_per_pair
						$paired_amount = $paired_unit * $pairing_amount_per_pair;
						$paired_comm[$uid][$pi]['paired_unit'] = $paired_unit;
						$paired_comm[$uid][$pi]['leg1'] = $member_legs[$prev_position]['position'];
						$paired_comm[$uid][$pi]['leg1_id'] = $member_legs[$prev_position]['id'];
						$paired_comm[$uid][$pi]['leg1_amount'] = $member_legs[$prev_position]['left_volume'];
						$paired_comm[$uid][$pi]['leg2'] = $member_legs[$cur_position]['position'];
						$paired_comm[$uid][$pi]['leg2_id'] = $member_legs[$cur_position]['id'];
						$paired_comm[$uid][$pi]['leg2_amount'] = $member_legs[$cur_position]['left_volume'];
						$pi++;
						$member_legs[$prev_position]['left_volume'] -= $paired_amount;
						$member_legs[$cur_position]['left_volume'] -= $paired_amount;
						if ($member_legs[$prev_position]['left_volume'] < $member_legs[$cur_position]['left_volume']){
							$prev_position = $cur_position;
						}
						//total_paired += paired_unit
						$total_paired += $paired_unit;
						//cur_position += 1
						$cur_position += 1;
						//continue_pair = true
						$continue_pair = true;
					}
				}
			}
		}while ($continue_pair);
		
		//carry forward for all legs with left_volume > 0
		for($j=0,$t2=count($member_legs);$j<$t2;$j++){
			if ($member_legs[$j]['left_volume'] > 0){
				//insert into member_cf with uid = member_legs[index][id], leg = member_legs[index][position], amount = member_legs[index][left_volume], year = year, month = month, day = day
				$sql="insert into $db->member_cf (uid, leg, amount, cdate) values ('{$member_legs[$j]['id']}', '{$member_legs[$j]['position']}', '{$member_legs[$j]['left_volume']}', '".date('Y-m-d', $start_time)."')";
				$insert_comm_detail="UID: $uid Carryforward Amount: {$member_legs[$j]['left_volume']} Leg: {$member_legs[$j]['position']} (DID: {$member_legs[$j]['id']})<br />\n";
				//if insert fail
					//record error in the variable insert_cf_error
				if(!mysql_query($sql)){
					$insert_cf_error.=$insert_comm_detail."SQL: $sql<br />\n";
				}
			}
		}
		
		//matching
		//if count(paired_comm[uid])
		if (count($paired_comm[$uid])){
			//downline_id = uid
			//level = 1
			$downline_id = $uid;
			if (!isset($member_info[$downline_id])){
				$member_info[$downline_id] = get_user_short_detail_by_id($downline_id);
			}
			if ($member_info[$downline_id]['primary_acc'] == 'y'){
				$primary_id = $uid;
			}else{
				$primary_id = $member_info[$downline_id]['primary_id'];
			}
			$level = 1;
			do{
				//if not isset member_info[downline_id]
				if (!isset($member_info[$downline_id])){
					//member_info[downline_id] = get member info of downline_id
					$member_info[$downline_id] = get_user_short_detail_by_id($downline_id);
				}
				//upline_id = get sponsor id of downline_id
				$upline_id = $member_info[$downline_id]['ref'];
				//if upline_id
				if ($upline_id){
					if (!isset($member_info[$upline_id])){
						$member_info[$upline_id] = get_user_short_detail_by_id($upline_id);
					}
					if ($member_info[$upline_id]['primary_acc'] == 'y' || $member_info[$upline_id]['primary_id'] == $primary_id){
					//only credit to upline if upline is not a sub-account, or upline is a sub-account and commission is originating from the same primary account
						//sponsor_tree[uid][level] = upline_id
						$sponsor_tree[$uid][$level] = $upline_id;
						$level += 1;
					}
					$downline_id = $upline_id;
				}else{
					unset($downline_id);
				}
			}while ($downline_id && $level <= $matching_max_level);
			
			//foreach paired_comm as uid => position_pair
			for($j=0,$t2=count($paired_comm[$uid]);$j<$t2;$j++){
				//unset pairing_id
				//pairing_comm_amount = paired_comm[uid][index][paired_unit] * pairing_bonus_per_pair
				unset ($pairing_id);
				$paired_unit = $paired_comm[$uid][$j]['paired_unit'];
				$pairing_comm_amount = $paired_unit * $pairing_bonus_per_pair;
				//insert the commission into the member_comm table with type = pairing, uid = uid, amount = pairing_comm_amount, leg1 = paired_comm[uid][index][leg1], leg1_id = paired_comm[uid][index][leg1_id], leg1_amount = paired_comm[uid][index][leg1_amount], leg2 = paired_comm[uid][index][leg2], leg2_id = paired_comm[uid][index][leg2_id], leg2_amount = paired_comm[uid][index][leg2_amount], paired_unit = paired_unit, year, month, datetime
				$sql="insert into $db->member_comm (uid, type, amount, leg1, leg1_id, leg1_amount, leg2, leg2_id, leg2_amount, paired_unit, year, month, day, status, cdate) values ('$uid', 'p', '$pairing_comm_amount', '{$paired_comm[$uid][$j]['leg1']}', '{$paired_comm[$uid][$j]['leg1_id']}', '{$paired_comm[$uid][$j]['leg1_amount']}', '{$paired_comm[$uid][$j]['leg2']}', '{$paired_comm[$uid][$j]['leg2_id']}', '{$paired_comm[$uid][$j]['leg2_amount']}', '$paired_unit', '$in_year', '$in_month', '$in_day', 'confirmed', '".ndate('Y-m-d H:i:s')."')";
				//if insert fail
					//record the error in the variable insert_pair_error
				$insert_comm_detail="UID: $uid Amount: $pairing_comm_amount Leg 1: {$paired_comm[$uid][$j]['leg1_id']}, Leg 2: {$paired_comm[$uid][$j]['leg2_id']} No. of Pair: $paired_unit<br />\n";
				if(!mysql_query($sql)){
					$insert_pair_error.=$insert_comm_detail."SQL: $sql<br />\n";
				}else{
					$insert_pair_success.=$insert_comm_detail;
					//pairing_id = last insert id
					$pairing_id = mysql_insert_id();
				}
				
				//if isset sponsor_tree[uid]
				if (isset($sponsor_tree[$uid])){
					//foreach sponsor_tree[uid] as level => upline_id
					foreach ($sponsor_tree[$uid] as $level => $upline_id){
						//if not isset upline_info[upline_id]
						if (!isset($upline_info[$upline_id])){
							//upline_info[upline_id][sponsor] = get total downline sponsored by this upline_id before the end of month of input in_date
							//upline_info[upline_id][activated] = whether this upline_id is activated
							$upline_info[$upline_id]['sponsor'] = @mysql_result(mysql_query("select count(*) from $db->users where ref='$upline_id' and cdate<='$calc_date[end]'"), 0) or 0;
							$upline_info[$upline_id]['activated'] = $member_info[$upline_id]['activated'];
						}
						//upline_detail = upline_info[upline_id]
						$upline_detail = $upline_info[$upline_id];
						//if upline_detail[volume] >= min_maintain and upline_detail[sponsor] >= matching_bonus[level][sponsor] and upline_detail[activated]
						if ($upline_detail['sponsor'] >= $matching_bonus[$level]['sponsor'] && $upline_detail['activated'] == 'y'){
							//matching_comm_amount = round(pairing_comm_amount * matching_bonus[level][percent] / 100, 2)
							$matching_comm_percent = $matching_bonus[$level]['percent'];
							$matching_comm_amount = round($pairing_comm_amount * $matching_comm_percent / 100, 2);
							//if pairing_id
							if ($pairing_id){
								//insert the commission into the member_comm table with type = matching, pid = pairing_id, uid = upline_id, from_uid = uid, amount = matching_comm_amount, level = level, percent = matching_bonus[level], year, month, datetime
								$sql="insert into $db->member_comm (uid, from_uid, type, pid, amount, level, percent, year, month, day, status, cdate) values ('$upline_id', '$uid', 'm', '$pairing_id', '$matching_comm_amount', '$level', '$matching_comm_percent', '$in_year', '$in_month', '$in_day', 'confirmed', '".ndate('Y-m-d H:i:s')."')";
								//if insert fail
									//record the error in the variable insert_matching_error
								$insert_comm_detail="UID: $uid Pairing ID: $pairing_id Amount: $matching_comm_amount Level: $level Percent: $matching_comm_percent%<br />\n";
								if(!mysql_query($sql)){
									$insert_matching_error.=$insert_comm_detail."SQL: $sql<br />\n";
								}else{
									$insert_matching_success.=$insert_comm_detail;
								}
							}else{
								//record the error in the variable insert_matching_error - pairing not properly inserted
								$insert_matching_error.="UID: $uid Pairing ID: Error! Amount: $matching_comm_amount Level: $level Percent: $matching_comm_percent%<br />\n";
							}
						}
					}
				}
			}
		}
	}
	
	if($insert_cf_error || $insert_pair_error || $insert_matching_error){
		$insert_errmsg.=($insert_cf_error? "Failed Recording Carry Forward:<br />\n<br />\n$insert_cf_error" : "").
		($insert_pair_error? "Failed Pairing Commission Calculation:<br />\n<br />\n$insert_pair_error" : "").
		($insert_matching_error? "Failed Matching Commission Calculation:<br />\n<br />\n$insert_matching_error" : "");
		$result["errmsg"] .= $insert_errmsg;
	}else{
		$result["status"] = true;
	}
	
	return $result;
}
?>